package top.mydb.hejianwei.dm;

import java.util.List;

import top.mydb.hejianwei.dm.page.Page;
import top.mydb.hejianwei.dm.page.PageX;
import top.mydb.hejianwei.dm.pageCache.PageCache;
import top.mydb.hejianwei.dm.pageIndex.PageIndex;
import top.mydb.hejianwei.dm.pageIndex.PageInfo;
import top.mydb.hejianwei.tm.TransactionManager;
import top.mydb.hejianwei.utils.Panic;

public class DataManagerImpl implements DataManager {
    private TransactionManager tm;
    private PageCache pc;
    private PageIndex pIndex;
    private Page pageOne; // 第一页，用于存储页面索引

    public DataManagerImpl(PageCache pc, TransactionManager tm) {
        this.tm = tm;
        this.pc = pc;
        this.pIndex = new PageIndex();

        try {
            // 加载第一页，用于页面索引
            pageOne = pc.getPage(1);
        } catch (Exception e) {
            // 如果是新创建的文件，第一页不存在，需要新建
            byte[] initRaw = PageX.initRaw();
            int pgno = pc.newPage(initRaw);
            assert pgno == 1; // 确保是第一页
            try {
                pageOne = pc.getPage(1);
            } catch (Exception e2) {
                Panic.panic(e2);
            }
        }
        
        // 从第一页加载页面索引
        List<PageInfo> piList = PageIndex.parsePageIndex(pageOne);
        for(PageInfo pi : piList) {
            pIndex.add(pi.pgno, pi.freeSpace);
        }
    }

    @Override
    public DataItem read(long uid) throws Exception {
        // UID由页号和页内偏移组成
        int pgno = (int)(uid >> 32);
        short offset = (short)(uid & ((1L << 32) - 1));

        Page pg = pc.getPage(pgno);
        
        // 从页面数据中解析出DataItem
        byte[] raw = pg.getData();
        // 此处需要一个逻辑来从raw+offset处解析出一条完整的数据项
        // 在当前简化版，我们先假设数据项就是我们存进去的字节数组
        // 并且暂时不处理数据的有效性（是否被删除等）
        // DataItem di = new DataItemImpl(pg, uid, this);
        // ...
        
        // 简化返回，暂时跳过DataItem的复杂解析
        return null;
    }

    @Override
    public long insert(long xid, byte[] data) throws Exception {
        // 在当前简化版，我们先假设所有数据都有效
        // 后面会加上 [ValidFlag] 1字节
        byte[] raw = data;

        // 1. 从页面索引中寻找一个有足够空间的页面
        PageInfo pi = pIndex.select(raw.length);
        Page pg;
        int pgno;

        if (pi == null) {
            // 2. 如果没有合适的页面，则创建新页
            pgno = pc.newPage(PageX.initRaw());
            pg = pc.getPage(pgno);
            pIndex.add(pgno, PageX.getFreeSpace(pg));
        } else {
            // 3. 如果找到了页面，直接获取
            pgno = pi.pgno;
            pg = pc.getPage(pgno);
        }

        // 4. 将数据插入页面
        short offset = PageX.insert(pg, raw);
        
        // 5. 更新页面索引信息
        pIndex.update(pgno, PageX.getFreeSpace(pg));

        // 6. 构造UID并返回
        long uid = ((long)pgno << 32) | (long)offset;
        return uid;
    }

    @Override
    public void close() {
        // 将页面索引刷回第一页
        PageIndex.flushPageIndex(pageOne, pIndex.getPageInfoList());
        pageOne.release();
        pc.close();
    }
}